/*
 * @Date: 2024-12-04 11:30:21
 * @Author: LiSong
 * @LastEditors: LiSong
 * @LastEditTime: 2025-02-26 16:02:12
 * @Description: 通用的首页设计数据源处理
 */

import { defAxios } from '@/utils/http'
import { DbSourceType } from '@hp/config/pojo'
import { isEmpty, isJSON, isArray, isObject, utf8ToBase64} from '@hp/utils/data.js'

import { useUserStore } from '@/stores/modules';
import { useDbSourceStore } from '@hp/stores/store-dbsource.js'
import { executeFuncText, createCustomException } from '@hp/utils/executeFunc.js'

// 方法前缀
const funcPrefix = 'func:'

/**
 * 将数据转换为json数据
 * 
 * @param {String} value 需要转换数据
 * @returns 转换后的json
 */
const parseDataToJSON = (value) => {
  try {
    let content = `return ${value}`
    const execFunc = new Function(content)
    content = execFunc()
    return content
    // return JSON.parse(value)
  } catch (error) {
    throw createCustomException(error, 'JSON数据解析出错');
  }
}

/**
 * 转换解析参数数据
 * 
 * @param {Array} paramCols 参数配置数组
 * @param {Object} params 额外参数数据
 * @returns 
 */
const parseParamsByArray = (paramCols, params) => {
  let result = {}
  if (!paramCols || !paramCols.length) return {}
  paramCols.forEach(item => {
    let itemRes = ''
    // 自定义获取参数方法存在
    if (item.paramRender) {
      itemRes = executeFuncText(item.paramRender, {
        errorTip: '请求参数解析出错！',
        paramNames: ['params'],
        paramObjects: { params }
      }) || ''
    } else {
      itemRes = item.defaultValue
    }
    // 数据类型转换
    itemRes = (item.kind === 1) ? Number(itemRes) : itemRes
    result[item.field] = itemRes
  })
  return result
}
/**
 * 转义接口请求的参数
 * 
 * @param {String} funcText 需要转换数据
 * @param {Object} params 额外的参数信息
 * @returns 
 */
const parseParamsByString = (funcText, params = {}) => {
  let result = {}
  if (!funcText || !funcText.replace(funcPrefix, '')) return {}
  if (funcText.startsWith(funcPrefix)) {
    result = executeFuncText(funcText, {
      resType: 'object',
      errorTip: '请求参数解析出错！',
      paramNames: ['params'],
      paramObjects: { params },
      defaultValue: {},
    }) || {}
  } else {
    result = parseDataToJSON(funcText)
  }
  return result
}
/**
 * 执行自定义的数据处理方法
 * 
 * @param {String} resFunc 请求后处理的自定义方法
 * @param {Object} resData 请求结果
 * @param {Object} params 额外的参数信息
 * @returns 
 */
const executeResponseFunc = (funcText, data, params) => {
  let result = data
  if (!funcText || !funcText.replace(funcPrefix, '')) return data
  result = executeFuncText(funcText, {
    resType: 'object',
    errorTip: '自定义数据处理函数解析出错！',
    paramNames: ['data', 'params'],
    paramObjects: { data, params },
    defaultValue: data,
  }) || data
  return result
}


export const useDbSource = (opts = {}) => {
  // 用户信息
  const userInfo = useUserStore().userInfo
  // 数据集
  const dbState = { ...opts, userInfo }
  // 接口调用的节流处理
  let serverTimeout = null
  // 数据集
  const dbSourceStore = useDbSourceStore()
  
  /**
   * 加载数据源
   * 
   * @param {Object} config 配置信息
   * @param {Object} extraParams 额外的参数
   * @returns 
   */
  const loadDataSource = async (schema, extraParams={}) => {
    const { dataSource: config, defaultValue } = schema
    if (!config || !config.type) return {}
    let res = null
    switch (config.type) {
      case DbSourceType.SQL.value:
        res = await loadSqlDataSource(config.sqlConfig, extraParams)
        break;
      case DbSourceType.VIEW.value:
        res = await loadViewDataSource(config.viewConfig, extraParams)
        break;
      case DbSourceType.STATIC.value:
        res = loadStaticDataSource(config.staticConfig, extraParams);
        break;
      case DbSourceType.SERVER.value:
        res = await loadServerDataSource(config.serverConfig, extraParams);
        break;
      default:
        break;
    }
    if (res) {
      // 解析COL
      analyseDataSourceCol(res, schema)
    } else {
      res = defaultValue || null
    }
    return res
  }

  /**
   * 加载SQL数据
   * 
   * @param {Object} config 配置信息，包含SQL语句
   * @returns {Promise<Object>} 加载的结果数据
   * @throws {Error} SQL数据请求出错
   */
  const loadSqlDataSource = async (config, extraParams={}) => {
    // 返回结果
    let result = null
    // 错误信息提示
    const errorTip = 'SQL数据请求出错！'
    return new Promise((resolve, reject) => {
      const sqlText = config.content
      if (!sqlText) {
        resolve(result)
      } else {
        if (serverTimeout) clearTimeout(serverTimeout)
        serverTimeout = setTimeout(() => {
          
          try {
            // 转义请求的查询参数
            const params = parseParamsByArray(config.paramColumns, dbState)
            // 请求参数配置
            const reqCfg = {
              url: '/data/process',
              method: 'post',
              data: {
                content: sqlText ? utf8ToBase64(sqlText) : sqlText,
                params: { ...params, ...extraParams }
              }
            }
            
            // 请求服务获取数据
            defAxios(reqCfg).then(res => {
              if (res.code === 200) {
                // 自定义数据处理的方法
                result = executeResponseFunc(config.responseFunc, res.data, dbState)
              } else {
                console.error(errorTip, res.msg)
              }
              resolve(result)
            }).catch(err => {
              resolve(result)
              console.error(errorTip, err)
            })
          } catch (error) {
            resolve(result)
            console.error(errorTip, error)
          }
        }, 1000)
      }
    })
  }

  /**
   * 加载视图数据
   * 
   * @param {Object} config 配置信息，包含视图编码、自定义的数据处理方法、请求参数等
   * @returns {Promise<Object>} 加载的结果数据
   * @throws {Error} 视图数据请求出错
   */
  const loadViewDataSource = (config, extraParams={}) => {
    // 返回结果
    let result = null
    // 错误信息提示
    const errorTip = '视图数据请求出错！'
    return new Promise((resolve, reject) => {
      if (!config.dataCode) {
        resolve(result)
      } else {
        try {
          const reqCfg = { url: '/dict/getDictData', method: 'post' }
          // 转义请求的查询参数
          const params = parseParamsByString(config.dataParams, dbState)
          reqCfg['data'] = { name: config.dataCode, ...params, ...extraParams }
          // 请求服务获取数据
          defAxios(reqCfg).then(res => {
            if (res.code === 200) {
              // 自定义数据处理的方法
              result = executeResponseFunc(config.responseFunc, res.data, dbState)
            } else {
              console.error(errorTip, res.msg)
            }
            resolve(result)
          }).catch(err => {
            resolve(result)
            console.error(errorTip, err)
          })
        } catch (error) {
          resolve(result)
          console.error(errorTip, error)
        }
      }
    })
  }

  /**
   * 加载静态数据
   * 
   * @param {Object} config 配置信息
   * @returns 处理后的结果数据
   */
  const loadStaticDataSource = (config) => {
    // 静态数据
    if (!config.dataValue) return null
    return parseDataToJSON(config.dataValue)
  }

  /**
   * 加载接口请求数据
   *
   * @param {Object} config 配置信息，包含请求的URL、请求方法、参数类型、请求参数以及自定义的响应处理函数
   * @returns {Promise<Object>} 加载的结果数据
   * @throws {Error} 如果请求解析出错，将会在控制台输出错误信息
   */
  const loadServerDataSource = (config, extraParams={}) => {
    // 返回结果
    let result = null
    // 错误信息提示
    const errorTip = '接口数据请求出错！'
    return new Promise((resolve, reject) => {
      if (!config.url) {
        resolve(result)
      } else {
        if (serverTimeout) clearTimeout(serverTimeout)
        serverTimeout = setTimeout(() => {
          try {
            const reqCfg = { url: config.url, method: config.method }
            // 转义请求的查询参数
            const params = parseParamsByString(config.params, dbState)
            reqCfg[config.paramsType] = { ...params, ...extraParams }
            // 请求服务获取数据
            defAxios(reqCfg).then(res => {
              if (res.code === 200) {
                // 自定义数据处理的方法
                result = executeResponseFunc(config.responseFunc, res.data, dbState)
              } else {
                console.error(errorTip, res.msg)
              }
              resolve(result)
            }).catch(respError => {
              resolve(result)
              console.error(errorTip, respError)
            })
          } catch (error) {
            resolve(result)
            console.error(errorTip, error)
          }
        }, 1000)
      }
    })
  }

  /**
   * 解析数据源的列
   * 
   * @param {Object} data 数据
   * @param {Object} schema 配置
   */
  const analyseDataSourceCol = (data, schema) => {
    const { id, dataSource } = schema
    const cacheKey = `${id}#${dataSource.type}`
    let keys = analyseObjectKeys(data, id, 'root')
    dbSourceStore.setDbCol(cacheKey, keys.map(item => ({ label: item, value: item })))
  }

  /**
   * 解析对象的key
   * 
   * @param {Any} data 
   * @param {String} id 
   * @param {String} pKey 
   * @returns 
   */
  const analyseObjectKeys = (data, id, pKey = '') => {
    if (isEmpty(data)) return []
    let keys = []
    if (isArray(data)) {
      keys = Object.keys(data[0])
    } else if (isJSON(data)) {
      keys = Object.keys(data)
      const cacheKey = [id, pKey]
      dbSourceStore.setDbChildCol(cacheKey.join('#'), keys.map(item => ({ label: item, value: item })))

      keys.forEach(key => {
        let item = data[key]
        if (isObject(item)) {
          const childKeys = analyseObjectKeys(item, id, key)
          keys = [...new Set([...keys, ...childKeys])]
        }
      })
    } else {
      keys = []
    }
    return keys
  }

  const loadDataCols = (schema) => {
    const { id, dataSource } = schema
    if (!dataSource) return []
    return dbSourceStore.colDic[`${id}#${dataSource.type}`] || []
  }

  const loadDataChildCols = (id, type) => {
    if (!type) return []
    return dbSourceStore.colChildDic[`${id}#${type}`] || []
  }

  return {
    loadDataCols,
    loadDataChildCols,
    loadDataSource,
    analyseObjectKeys,
  }
}
